home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / Samples / Moofwars 1.02 / MoofWars Sprocket / •Source / TCommandTimer.cp < prev    next >
Encoding:
Text File  |  1998-08-10  |  7.0 KB  |  296 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************
  2. Command.cp
  3.  
  4. The command section accomplishes two things for the game -- first, providing a
  5. standard clock to which all actions can be synchonized, and second, grabbing the state
  6. of the keyboard to pass along to those game parts that need it.
  7.  
  8. This code implements a time manager task that periodically grabs the state of the
  9. keyboard.  It stores these in a buffer where the main application task can retrieve it.
  10.  
  11. We create a buffer for two seconds worth of commands, although in practice we'll almost
  12. never need more than about a 1/10 of a second.
  13.  
  14. Eventually, this code will also probably need to deal with networking tasks.
  15.  
  16. Author: Timothy Carroll
  17. Apple Developer Technical Support
  18. timc@apple.com
  19.  
  20. Modification History: 
  21.  
  22. 8/7/98        TMC     Moved code over from VBL to time manager task.
  23. 1/26/97        TMC        Now explicitly includes MoofWars.h
  24. 8/15/96        TMC     Initial Release         
  25.  
  26. Copyright © 1996, 1997 Apple Computer, Inc., All Rights Reserved
  27.  
  28. You may incorporate this sample code into your applications without
  29. restriction, though the sample code has been provided "AS IS" and the
  30. responsibility for its operation is 100% yours.  However, what you are
  31. not permitted to do is to redistribute the source as "DSC Sample Code"
  32. after having made changes. If you're going to re-distribute the source,
  33. we require that you make it clear in the source that the code was
  34. descended from Apple Sample Code, but that you've made changes.
  35.  
  36. *************************************************************************************/
  37.  
  38. #include <Errors.h>
  39. #include <Timer.h>
  40.  
  41. #include "AppConditionals.h"
  42. #include "Error Macros.h"
  43. #include "TCommandTimer.h"
  44.  
  45. #if !TARGET_RT_MAC_CFM
  46. #error This code is not useable on classic 68K architectures.
  47. #endif
  48.  
  49. struct CommandTimerData
  50. {
  51.     TMTask        fTimer;
  52.     Boolean        fRunning;
  53.     SInt16        fFramesPerSecond;
  54.     SInt16        fBufferSize;
  55.     TInputState    *fCommandBuffer;
  56.     // these hold our current locations in the buffer
  57.     SInt16        fInCommandIndex;
  58.     SInt16        fOutCommandIndex;
  59.     TimerUPP    fCommandTimerUPP;
  60.     SInt32        timerDelay;
  61. } *CommandTimerPtr;
  62.  
  63. // The actual timer task that gets called to retrieve inputs.
  64. void CommandTimer (TMTaskPtr recPtr);
  65.  
  66.  
  67. TCommandTimer::TCommandTimer (void)
  68. {
  69.     timerData = NULL;
  70. }
  71.  
  72. TCommandTimer::~TCommandTimer (void)
  73. {
  74.     if (timerData == NULL)
  75.         return;
  76.     
  77.     if (timerData->fRunning)
  78.         this->AcceptCommands(false);
  79.         
  80.     if (timerData->fCommandTimerUPP != NULL)
  81.         DisposeRoutineDescriptor (timerData->fCommandTimerUPP);
  82.         
  83.     if (timerData->fCommandBuffer != NULL)
  84.         DisposePtr ((Ptr) timerData->fCommandBuffer);
  85.     
  86.     DisposePtr ((Ptr) timerData);
  87.     timerData = NULL;
  88. }
  89.  
  90. OSStatus TCommandTimer::Initialize (SInt16 framesDesired)
  91. {
  92.     OSStatus theErr = noErr;
  93.     
  94. #if qDebugging
  95.     if (timerData != NULL)
  96.         SIGNAL_ERROR("\pError: TCommandTimer may only be initialized once");
  97. #endif
  98.  
  99.     // Allocate all the data structures
  100.     
  101.     timerData = (CommandTimerData *) NewPtrClear (sizeof (CommandTimerData));
  102.     theErr = MemError();
  103.     FAIL_OSERR (theErr, "\pError: Failed to allocate CommandTimerData")
  104.     
  105.     timerData->fFramesPerSecond = framesDesired;
  106.     timerData->fBufferSize = 2 * timerData->fFramesPerSecond;
  107.     
  108.     if (framesDesired == 0) // Special case -- we're not actually using a timer!
  109.         goto cleanup;
  110.     
  111.     timerData->fCommandBuffer = (TInputState *) NewPtrClear (sizeof (TInputState) * timerData->fBufferSize);
  112.     theErr = MemError();
  113.     FAIL_OSERR (theErr, "\pError: Failed to allocate commands buffer")
  114.         
  115.     timerData->fCommandTimerUPP = NewTimerProc (CommandTimer);
  116.     if (timerData->fCommandTimerUPP == NULL)
  117.         SIGNAL_ERROR ("\pError: Unable to allocate the timer UPP")
  118.     
  119.     // Set up the time manager data.  We don't actually install the task until we activate the timer.
  120.         
  121.     timerData->fTimer.tmAddr = timerData->fCommandTimerUPP;
  122.     //timerData->timerDelay = - (1000000/timerData->fFramesPerSecond); // amount of time per frame in microseconds
  123.     timerData->timerDelay = 1000/timerData->fFramesPerSecond;
  124.     goto cleanup;
  125.  
  126. error:
  127.     if (theErr == noErr)
  128.         theErr = paramErr;
  129.     // everything else is cleaned up by the regular destructor.
  130.     
  131. cleanup:
  132.  
  133.     return theErr;
  134. }
  135.  
  136.  
  137. Boolean TCommandTimer::IsAcceptingCommands (void)
  138. {
  139. #if qDebugging
  140.     if (timerData == NULL)
  141.         SIGNAL_ERROR("\pError: TCommandTimer must be initialized!");
  142. #endif
  143.  
  144.     if (timerData->fFramesPerSecond == 0)
  145.         return true;
  146.         
  147.     return timerData->fRunning;
  148.     
  149.     error:
  150.     
  151.     return false;
  152.     
  153. }
  154.  
  155. void TCommandTimer::AcceptCommands (Boolean commands)
  156. {
  157. #if qDebugging
  158.     if (timerData == NULL)
  159.         SIGNAL_ERROR("\pError: TCommandTimer must be initialized!");
  160. #endif
  161.  
  162.     if (timerData->fFramesPerSecond == 0)
  163.     {
  164.         return;
  165.     }
  166.  
  167.     if (timerData->fRunning == commands)
  168.         return;
  169.     
  170.     
  171.     if (commands)
  172.     {
  173.         timerData->fRunning = true;
  174.         // tn1063 documents that we need to clear these fields to make sure nothing wacky happens.
  175.         timerData->fTimer.qLink = NULL;
  176.         timerData->fTimer.tmReserved = 0;
  177.         InsXTime ((QElemPtr) &timerData->fTimer);
  178.         PrimeTime ((QElemPtr) &timerData->fTimer, timerData->timerDelay);
  179.     }
  180.     else
  181.     {
  182.         timerData->fRunning = false;
  183.         RmvTime((QElemPtr) &timerData->fTimer);
  184.     }
  185.  
  186.     error:
  187.         return;
  188. }
  189.         
  190. void TCommandTimer::FlushCommands(void)
  191. {
  192. #if qDebugging
  193.     if (timerData == NULL)
  194.         SIGNAL_ERROR("\pError: TCommandTimer must be initialized!");
  195.         
  196.     if (timerData->fRunning)
  197.         SIGNAL_ERROR ("\pError: TCommandTimer must not be accepting commands");
  198. #endif
  199.  
  200.     if (timerData->fFramesPerSecond == 0)
  201.     {
  202.         return;
  203.     }
  204.  
  205.     timerData->    fInCommandIndex = timerData->fOutCommandIndex = 0;
  206. error:
  207.     return;
  208. }
  209.         
  210. Boolean TCommandTimer::IsCommandWaiting (void)
  211. {
  212. #if qDebugging
  213.     if (timerData == NULL)
  214.         SIGNAL_ERROR("\pError: TCommandTimer must be initialized!");
  215. #endif
  216.  
  217.     if (timerData->fFramesPerSecond == 0)
  218.     {
  219.         return true;
  220.     }
  221.  
  222.     if (timerData->fInCommandIndex != timerData->fOutCommandIndex)
  223.         return true;
  224. error:
  225.     return false;
  226. }
  227.  
  228. Boolean TCommandTimer::RetrieveCommand (TInputState *command)
  229. {
  230.     Boolean peek;
  231.     
  232.     if (timerData->fFramesPerSecond == 0)
  233.     {
  234.         GetKeys (command->keys);
  235.         return true;
  236.     }
  237.     
  238.     peek = this->PeekCommand (command);
  239.     
  240.     if (peek)
  241.         timerData->fOutCommandIndex = (timerData->fOutCommandIndex +1) % (timerData->fBufferSize);
  242.     
  243.     return peek;
  244.     
  245. }
  246.  
  247. Boolean TCommandTimer::PeekCommand (TInputState *command)
  248. {
  249.     SInt16 index;
  250.     
  251. #if qDebugging
  252.     if (timerData == NULL)
  253.         SIGNAL_ERROR("\pError: TCommandTimer must be initialized!");
  254. #endif
  255.  
  256.     if (timerData->fFramesPerSecond == 0)
  257.     {
  258.         GetKeys (command->keys);
  259.         return true;
  260.     }
  261.  
  262.     if (timerData->fInCommandIndex == timerData->fOutCommandIndex)
  263.         return false;
  264.     
  265.     index = (timerData->fOutCommandIndex +1) % (timerData->fBufferSize);
  266.     *command = (timerData->fCommandBuffer)[index];
  267.     
  268.     return true;
  269.     
  270. error:
  271.     return false;
  272. }
  273.     
  274.  
  275. void CommandTimer (TMTaskPtr recPtr)
  276. {
  277.     CommandTimerData *timerData = (CommandTimerData *) recPtr;
  278.     SInt16 index;
  279.     
  280.     if (!timerData->fRunning)
  281.         return;
  282.     
  283.     index = (timerData->fInCommandIndex+1) % timerData->fBufferSize;
  284.     
  285.     if (index != timerData->fOutCommandIndex)
  286.     {
  287.         timerData->fInCommandIndex = index;
  288.         GetKeys (((timerData->fCommandBuffer)[index]).keys);
  289.     }
  290.  
  291.     // Reset the timer
  292.     
  293.     PrimeTime((QElemPtr) &timerData->fTimer, timerData->timerDelay);
  294.  
  295. }
  296.